package com.share.tool.mock.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.share.common.common.Page;
import com.share.common.utils.DateExtUtil;
import com.share.common.utils.RandomUtil;
import com.share.common.utils.StrUtil;
import com.share.tool.mock.mapper.HttpVariableMapper;
import com.share.tool.mock.model.db.HttpVariable;
import com.share.tool.mock.model.db.Variable;
import com.share.tool.mock.model.dto.McParam;
import com.share.tool.mock.model.vo.HttpPageListReq;
import com.share.tool.mock.model.vo.KvVar;
import com.share.tool.mock.service.HttpVariableService;
import com.share.tool.mock.service.VariableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class HttpVariableServiceImpl extends ServiceImpl<HttpVariableMapper, HttpVariable> implements HttpVariableService {
    @Autowired
    private VariableService mockVariableService;

    @Autowired
    private HttpVariableMapper mockHttpVariableMapper;

    private Map<String, HttpVariable> httpConfigMap;

    @Override
    public HttpVariable getByCode(String code) {
        return httpConfigMap.get(code);
    }

    @Override
    public Object init() {
        LambdaQueryWrapper<HttpVariable> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HttpVariable::getIsValid, 1);
        List<HttpVariable> list = mockHttpVariableMapper.selectList(queryWrapper);
        Map<String, HttpVariable> tmpHttpMorkConfigMap = new HashMap<>();
        for (HttpVariable item : list) {
            tmpHttpMorkConfigMap.put(item.getCode(), item);
        }

        if (tmpHttpMorkConfigMap != null) {
            httpConfigMap = tmpHttpMorkConfigMap;
        }
        return httpConfigMap;
    }

    /*根据表mock出http的数据*/
    @Override
    public Object httpMock(@NotNull HttpVariable httpMorkConfig, @NotNull McParam mcParam) {
        Object reObj = null;
        String reOrginValue = httpMorkConfig.getValue();
        String reDataType = httpMorkConfig.getFormat();
        JSONObject varParam = mcParam.get_varParam();

        //获取变量列表
        String variables = httpMorkConfig.getVariables();
        if (StringUtils.isNotBlank(variables)) {
            String[] vars = variables.split(",");
            for (String kvStr : vars) {
                //空的直接跳过
                if (StringUtils.isBlank(kvStr)) {
                    continue;
                }

                //加载kv和加载配置
                KvVar kvVar = calcKv(kvStr);
                String replaceName = kvVar.getReplaceName();
                String varName = kvVar.getVarName();
                Variable morkVariable = mockVariableService.getByVariableCode(varName);

                //变量的取值---优先从cache中获取
                Object value = varParam.get(replaceName);
                if (value == null) {
                    String tmpStr = JSON.toJSONString(mcParam);//这里是所有参数---groovy使用搜索获取值
                    value = calcVarValue(kvVar, tmpStr, null);
                    varParam.put(replaceName, value);
                }
                String reValue = (value == null) ? morkVariable.getDefaultValue() : value.toString();

                //替换目标的值---数字如果要表示为字符串需要用2层双引号
                String varDataType = StringUtils.isBlank(morkVariable.getDataType()) ? "string" : morkVariable.getDataType();
                if (varDataType.contains("json")) {
                    // {"aa":"#444#"}  替换后不是json结构
                    if (reOrginValue.indexOf("\"#" + replaceName + "#\"") > 0) {
                        //希望时字符串
                        reOrginValue = reOrginValue.replaceAll("#" + replaceName + "#", StrUtil.addEscape(reValue, '"'));
                    } else {
                        //希望是json对象
                        reOrginValue = reOrginValue.replaceAll("#" + replaceName + "#", reValue);
                    }
                } else {
                    // {"aa":"#444#"}  常规结构由 组合的地方决定
                    reOrginValue = reOrginValue.replaceAll("#" + replaceName + "#", reValue);
                }

                reObj = reOrginValue;
            }
        }

        //中间过程不能 转json---因为部分值还没替换
        if ("json".contains(reDataType)) {
            reObj = JSON.parseObject(reOrginValue);
        }

        //执行延迟
        sleep(httpMorkConfig);

        return reObj;
    }

    //延迟喊出
    private void sleep(HttpVariable config) {
        //开关
        String delayWay = config.getDelayWay();
        if (StringUtils.isBlank(delayWay) || "0".equals(delayWay)) {
            return;
        }

        //随机是否命中 是否有效
        boolean randomSwith = false;
        if (config.getDelayRate() == null || config.getDelayRate() >= 1) {
            randomSwith = true;
        } else {
            Integer random = RandomUtil.getRandom(1000);
            Double rate = Math.abs(config.getDelayRate() * 1000);
            if (random < rate) {
                randomSwith = true;
            } else {
                randomSwith = false;
            }
        }
        if (!randomSwith) {
            return;
        }

        //延时参数未配置
        Integer delayMin = config.getDelayMin();
        Integer delayMax = config.getDelayMax();
        if (delayMax == null || delayMin == null) {
            //参数未配置完毕
            log.warn("延时基数delayMax或delayMax没有配置");
            return;
        }

        //时间是否有效
        boolean timeSwitch = false;
        String time = null;
        String startTime = null;
        String endTime = null;
        if ("1".equals(delayWay)) {
            time = DateExtUtil.getTime();

            Date delayStartTime = config.getDelayStartTime();
            if (delayStartTime != null) {
                startTime = DateExtUtil.getTime(delayStartTime);
            }

            Date delayEndTime = config.getDelayEndTime();
            if (delayEndTime != null) {
                endTime = DateExtUtil.getTime(delayEndTime);
            }
        } else if ("2".equals(delayWay)) {
            time = DateExtUtil.getDateTime();

            Date delayStartTime = config.getDelayStartTime();
            if (delayStartTime != null) {
                startTime = DateExtUtil.getDateTime(delayStartTime);
            }

            Date delayEndTime = config.getDelayEndTime();
            if (delayEndTime != null) {
                endTime = DateExtUtil.getDateTime(delayEndTime);
            }
        }
        if (startTime == null && endTime == null) {
            timeSwitch = true;
        } else if (startTime == null && endTime.compareTo(time) >= 0) {
            timeSwitch = true;
        } else if (endTime == null && startTime.compareTo(time) >= 0) {
            timeSwitch = true;
        } else if (startTime.compareTo(time) >= 0 && endTime.compareTo(time) >= 0) {
            timeSwitch = true;
        }

        //开始延迟
        if (timeSwitch && randomSwith) {
            try {
                Integer sleepTime = RandomUtil.rangMinMax(delayMin, delayMax);
                Thread.sleep(sleepTime);
            } catch (Exception e) {

            }
        }
    }

    @Override
    public Page pageList(HttpPageListReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<HttpVariable> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(req.getCode())) {
            queryWrapper.like(HttpVariable::getCode, req.getCode());
        }
        if (StringUtils.isNotBlank(req.getName())) {
            queryWrapper.like(HttpVariable::getName, req.getName());
        }
        if (StringUtils.isNotBlank(req.getVariables())) {
            queryWrapper.like(HttpVariable::getVariables, req.getVariables());
        }
        if (StringUtils.isNotBlank(req.getValue())) {
            queryWrapper.like(HttpVariable::getValue, req.getValue());
        }
        List<HttpVariable> list = mockHttpVariableMapper.selectList(queryWrapper);
        return new Page<>(list, new PageInfo<>(list).getTotal(), req);
    }

    //切割kv
    private KvVar calcKv(String kvVarStr) {
        KvVar kvVar = null;
        if (StringUtils.isNotBlank(kvVarStr)) {
            kvVar = new KvVar();
            String[] kvTmp = kvVarStr.split("=");
            if (kvTmp.length == 1) {//idCard,name
                kvVar.setReplaceName(kvTmp[0]);
                kvVar.setVarName(kvTmp[0]);
                kvVar.setExeWay("0");
            } else if (kvTmp.length == 2) {////idCard=$.a,name=name
                kvVar.setReplaceName(kvTmp[0]);
                if (kvTmp[0].startsWith("$")) {
                    kvVar.setVarName(kvTmp[0]);
                    kvVar.setExeWay("1");
                } else {
                    kvVar.setVarName(kvTmp[1]);
                    kvVar.setExeWay("0");
                }
            }
        }

        return kvVar;
    }

    /**
     * 执行groovy脚本
     *
     * @param kvVar   变量
     * @param jsonStr 请求的参数
     * @return
     */
    private Object calcVarValue(KvVar kvVar, String jsonStr, Object defaultValue) {
        Object value = null;
        String variable = kvVar.getVarName();
        try {
            //变量的取值
            if ("1".equals(kvVar.getExeWay())) {//jsonpath
                value = JSONPath.eval(jsonStr, kvVar.getJsonPath());
            } else {
                //使用groovy脚本处理
                value = mockVariableService.exeGroovyScript(variable, "parseJson", jsonStr);
            }
        } catch (Exception e) {
            //异常不打印
            log.error("groovy脚本执行异常morkVariable={}", variable, e);
            value = defaultValue;
        }
        return value;
    }

    /**
     * 执行groovy脚本
     *
     * @param kvVars  变量列表,也就是需要的数据名字
     * @param mcParam 请求的参数
     * @return
     */
    @Override
    public Map<String, Object> calcValues(String kvVars, McParam mcParam) {
        //计算变量的值
        Map<String, Object> reMap = new HashMap<>();
        Set<String> variableList = Arrays.stream(Optional.ofNullable(kvVars).orElse("").split(",")).map(m -> m.trim()).filter(f -> StringUtils.isNotBlank(f)).collect(Collectors.toSet());
        for (String kvVarStr : variableList) {
            if (StringUtils.isBlank(kvVarStr)) {
                continue;
            }
            KvVar kvVar = calcKv(kvVarStr);
            Variable morkVariable = mockVariableService.getByVariableCode(kvVar.getVarName());
            String jsonStr = JSON.toJSONString(mcParam);
            Object value = calcVarValue(kvVar, jsonStr, morkVariable.getDefaultValue());

            reMap.put(kvVar.getReplaceName(), value);
        }
        return reMap;
    }
}
